package ca.scotthyndman.as2haxe.dom;

import java.util.ArrayList;
import java.util.List;

import ca.scotthyndman.as2haxe.dom.visitor.IVisitor;

/**
 * Represents an instanceof expression.
 */
public class ASInstanceOfExpression extends ASExpression {

	/**
	 * The "leftOperand" structural property of this node type.
	 * 
	 * @since 3.0
	 */
	public static final ASChildPropertyDescriptor LEFT_OPERAND_PROPERTY = new ASChildPropertyDescriptor(
			ASInstanceOfExpression.class,
			"leftOperand", ASExpression.class, true); //$NON-NLS-1$

	/**
	 * The "rightOperand" structural property of this node type.
	 * 
	 * @since 3.0
	 */
	public static final ASChildPropertyDescriptor RIGHT_OPERAND_PROPERTY = new ASChildPropertyDescriptor(
			ASInstanceOfExpression.class,
			"rightOperand", ASQualifiedName.class, true); //$NON-NLS-1$

	/**
	 * A list of property descriptors (element type:
	 * {@link ASPropertyDescriptor}), or null if uninitialized.
	 */
	private static final List<ASPropertyDescriptor> PROPERTY_DESCRIPTORS;

	static {
		List<Object> properyList = new ArrayList<Object>(3);
		createPropertyList(ASInstanceOfExpression.class, properyList);
		addProperty(LEFT_OPERAND_PROPERTY, properyList);
		addProperty(RIGHT_OPERAND_PROPERTY, properyList);
		PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
	}

	/**
	 * Returns a list of structural property descriptors for this node type.
	 * Clients must not modify the result.
	 * 
	 * @return a list of property descriptors
	 */
	public static List<ASPropertyDescriptor> propertyDescriptors() {
		return PROPERTY_DESCRIPTORS;
	}

	//
	// ======== MEMBERS
	//

	private ASExpression leftOperand;

	private ASQualifiedName rightOperand; // FIXME this should be a type

	/**
	 * Constructs a new instance of ASInstanceOfExpression
	 * 
	 * @param ast
	 *            The abstract syntax tree that owns this element
	 */
	public ASInstanceOfExpression(AST ast) {
		super(ast);
	}

	/**
	 * Sets the left operand.
	 * 
	 * @param leftOperand
	 *            the new left operand
	 */
	public void setLeftOperand(ASExpression leftOperand) {
		if (leftOperand == null) {
			throw new IllegalArgumentException();
		}
		// an Assignment may occur inside a Expression - must check cycles
		ASTNode oldChild = this.leftOperand;
		preReplaceChild(oldChild, leftOperand, LEFT_OPERAND_PROPERTY);
		this.leftOperand = leftOperand;
		postReplaceChild(oldChild, leftOperand, LEFT_OPERAND_PROPERTY);
	}

	/**
	 * Returns the left operand.
	 * 
	 * @return the left operand
	 */
	public ASExpression getLeftOperand() {
		return leftOperand;
	}

	/**
	 * Sets the right operand.
	 * 
	 * @param rightOperand
	 *            the new right operand
	 */
	public void setRightOperand(ASQualifiedName rightOperand) {
		if (rightOperand == null) {
			throw new IllegalArgumentException();
		}
		// an Assignment may occur inside a Expression - must check cycles
		ASTNode oldChild = this.rightOperand;
		preReplaceChild(oldChild, rightOperand, RIGHT_OPERAND_PROPERTY);
		this.rightOperand = rightOperand;
		postReplaceChild(oldChild, rightOperand, RIGHT_OPERAND_PROPERTY);
	}

	/**
	 * Returns the right operand.
	 * 
	 * @return the right operand
	 */
	public ASQualifiedName getRightOperand() {
		return rightOperand;
	}

	//
	// ======== INTERNAL
	//

	/*
	 * (omit javadoc for this method) Method declared on ASTNode.
	 */
	final ASTNode internalGetSetChildProperty(
			ASChildPropertyDescriptor property, boolean get, ASTNode child) {
		if (property == LEFT_OPERAND_PROPERTY) {
			if (get) {
				return getLeftOperand();
			} else {
				setLeftOperand((ASExpression) child);
				return null;
			}
		}
		if (property == RIGHT_OPERAND_PROPERTY) {
			if (get) {
				return getRightOperand();
			} else {
				setRightOperand((ASQualifiedName) child);
				return null;
			}
		}
		// allow default implementation to flag the error
		return super.internalGetSetChildProperty(property, get, child);
	}

	// ===== TO STRING AND VISITOR

	@Override
	public String toString() {
		return getLeftOperand().toString() + " instanceof "
				+ getRightOperand().toString();
	}

	@Override
	public void accept(IVisitor as2Visitor, boolean recursive) {
		recursive = as2Visitor.visit(this);

		if (!recursive) {
			return;
		}

		getLeftOperand().accept(as2Visitor, recursive);
		getRightOperand().accept(as2Visitor, recursive);
	}
}
